
#include "stdafx.h"
#include "Win32.Base64Encoding.h"

// -----------------------------------------------------------------------------

namespace Kif
{
namespace Win32
{
namespace Text
{
namespace Encoding
{

// -----------------------------------------------------------------------------

/// <summary>Find text in decoded item and return a pointer to the next char
/// of found key-value</summary>
/// <param name="buffer">buffer in were to find string. Buffer must be withing
/// "Data" range, else NULL will be returned</param>
/// <param name="text">text string to find</param>
/// <param name="textLength">text string length</param>
/// <param name="keyValue">Output key-value</param>
/// <param name="delimiter">delimiter for key-value</param>
/// <results>a pointer last scanned char is returned if found,
/// else NULL is returned</results>
TCHAR *DecodedItem::Find(TCHAR *buffer, TCHAR *text, size_t textLength,
   Kif::Win32::ItemKeyValue &keyValue, TCHAR *delimiter)
{
   // validate given buffer pointer...
   if (buffer == NULL)
      buffer = Data;
   if ((buffer < Data) || (buffer >= Data + DataLength))
      return NULL;
   size_t bufferLength = DataLength - (buffer - Data);

   // try to find string...
   keyValue.Dispose();
   TCHAR *foundStr =
      Kif::Win32::String::FindBinaryItem(buffer,bufferLength,text,textLength);
   if (!foundStr)
      return(false);

   keyValue.Key.Copy(text,textLength);
   foundStr += textLength;

   // eat-trailer blanks and match delimiter...
   while(*foundStr && (*foundStr <= ' '))
      foundStr;
   while(*foundStr && (*foundStr == *delimiter))
   {
      foundStr++;
      delimiter++;
   }
   while(*foundStr && (*foundStr <= ' '))
      foundStr;

   // find string till a none-printable char is found
   size_t l = 0;
   while(*(foundStr+l) && (*(foundStr+l) > ' '))
      l++;
   keyValue.Value.Copy(foundStr,l);

   return(keyValue.Value.GetLength() > 0 ? foundStr + l : NULL);
}  // end of Find

// -----------------------------------------------------------------------------

/// <summary>Decode given item with given encoding type</summary>
/// <param name="encoding">Encoding</param>
/// <param name="sourceEncodedItem">Source Encoded Item</param>
/// <param name="sourceEncodedItemLength">Source Encoded Item Length</param>
/// <results>true is returned if item was decoded</results>
bool DecodedItem::Decode(EncodingType encoding,
   TCHAR *sourceEncodedItem, size_t sourceEncodedItemLength)
{
   bool done = false;
   Dispose();
   if (encoding == EncodingType_Base64)
   {
      Encoding = encoding;

      size_t outMaxLen = sourceEncodedItemLength;
      Data = (TCHAR*)Kif::Win32::Memory::alloc(sizeof(TCHAR) * (outMaxLen));

      size_t outLength;
      Kif::Win32::Text::Encoding::EncodingError result =
         Kif::Win32::Text::Encoding::Base64::Decode(
            Data, outMaxLen,
            sourceEncodedItem, sourceEncodedItemLength,
            &outLength);

      if (result != Kif::Win32::Text::Encoding::EncodingError_Success)
         Dispose();
      else
      {
         DataLength = outLength;
         done = true;
      }

      Status = result;
   }
   return(done);
}  // end of Decode

// -----------------------------------------------------------------------------

/* 
 * MIME Base64 coding examples 
 * 
 * encode() encodes an arbitrary data block into MIME Base64 format string 
 * decode() decodes a MIME Base64 format string into raw data 
 * 
 * Global table base64[] carries the MIME Base64 conversion characters 
 */ 

/* 
 * Global data used by both binary-to-base64 and base64-to-binary conversions 
 */ 

static char base64[] =
   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 

/* 
 *  ENCODE RAW into BASE64 
 */ 

/* Encode source from raw data into Base64 encoded string */ 
//int encode(unsigned s_len, char *src, unsigned d_len, char *dst) 
//{ 
//      unsigned triad; 
//
//      for (triad = 0; triad < s_len; triad += 3) 
//      { 
//            unsigned long int sr; 
//            unsigned byte; 
//
//
//            for (byte = 0; (byte<3)&&(triad+byte<s_len); ++byte) 
//            { 
//                  sr <<= 8; 
//                  sr |= (*(src+triad+byte) & 0xff); 
//            } 
//
//
//            sr <<= (6-((8*byte)%6))%6;  /*shift left to next 6bit alignment*/ 
//
//
//            if (d_len < 4) return 1;      /* error - dest too short */ 
//
//
//            *(dst+0) = *(dst+1) = *(dst+2) = *(dst+3) = '='; 
//            switch(byte) 
//            { 
//                  case 3: 
//                        *(dst+3) = base64[sr&0x3f]; 
//                        sr >>= 6; 
//                  case 2: 
//                        *(dst+2) = base64[sr&0x3f]; 
//                        sr >>= 6; 
//                  case 1: 
//                        *(dst+1) = base64[sr&0x3f]; 
//                        sr >>= 6; 
//                        *(dst+0) = base64[sr&0x3f]; 
//            } 
//            dst += 4; d_len -= 4; 
//      } 
//
//
//      return 0; 
//} 

/* 
 *  DECODE BASE64 into RAW 
 */ 

/* determine which sextet value a Base64 character represents */ 
int tlu(int byte) 
{ 
   int index; 

   for (index = 0; index < 64; ++index) 
         if (base64[index] == byte) 
               break; 
   if (index > 63) index = -1; 
   return index; 
}  // end of tlu

/* 
 * Decode source from Base64 encoded string into raw data 
 * 
 * Returns: 0 - Success 
 *          1 - Error - Source underflow - need more base64 data 
 *          2 - Error - Chunk contains half a byte of data 
 *          3 - Error - Decoded results will overflow output buffer 
 *          4 - Error - outLength (output length) is NULL! 
 */ 

EncodingError Base64::Decode(
   //unsigned s_len, char *src, unsigned d_len, char *dst) 
   TCHAR *outString, size_t outMaxLength,
   TCHAR *inString,  size_t inLength,
   size_t *outLength)
{
   if (!outLength)
      return EncodingError_OutputLengthIsNull;

   *outLength = 0;
   unsigned s_len = inLength;
   unsigned d_len = outMaxLength;
   TCHAR *src = inString;
   TCHAR *dst = outString;

   unsigned six, dix; 
   dix = 0; 

   for (six = 0; six < s_len; six += 4) 
   { 
      unsigned long sr; 
      unsigned ix; 

      sr = 0; 
      for (ix = 0; ix < 4; ++ix) 
      { 
         int sextet; 

         if (six+ix >= s_len) 
               return EncodingError_SourceUnderflowNeedMoreData; 
         if ((sextet = tlu(*(src+six+ix))) < 0) 
               break; 
         sr <<= 6; 
         sr |= (sextet & 0x3f); 
      } 

      switch (ix) 
      { 
         case 0:     /* end of data, no padding */ 
            *outLength = dix;
            return EncodingError_Success; 

         case 1:     /* can't happen */ 
            return EncodingError_ChunkContainsHalfByteData; 

         case 2: /* 1 result byte */ 
            sr >>= 4; 
            if (dix > d_len)
               return EncodingError_DecodedOverflow; 
            *(dst+dix) = (sr & 0xff); 
            ++dix; 
            break; 

         case 3:     /* 2 result bytes */ 
            sr >>= 2; 
            if (dix+1 > d_len)
               return EncodingError_DecodedOverflow; 
            *(dst+dix+1) = (sr & 0xff); 
            sr >>= 8; 
            *(dst+dix) = (sr & 0xff); 
            dix += 2; 
            break; 

         case 4:     /* 3 result bytes */ 
            if (dix+2 > d_len)
               return EncodingError_DecodedOverflow; 
            *(dst+dix+2) = (sr & 0xff); 
            sr >>= 8; 
            *(dst+dix+1) = (sr & 0xff); 
            sr >>= 8; 
            *(dst+dix) = (sr & 0xff); 
            dix += 3; 
            break; 
      } 
   } 
   *outLength = dix;
   return EncodingError_Success; 
}  // end of Decode

}  // end of Kif::Win32::Text::Encoding namespace
}  // end of Kif::Win32::Text namespace
}  // end of Kif::Win32 namespace
}  // end of Kif namespace


